{
    function Foo() {
        Foo.a = function () {
            console.log(1)
        }
        this.a = function () {
            console.log(2)
        }
    }
    Foo.prototype.a = function () {
        console.log(3)
    };
    Foo.a = function () {
        console.log(4)
    };
    Foo.a(); //4
    let obj = new Foo();
    obj.a(); // 2
    Foo.a(); // 1
}

{
    function changeObjProperty(o) {
        o.siteUrl = "http://www.baidu.com"
        o = new Object()
        o.siteUrl = "http://www.google.com"
    }
    let webSite = new Object();
    changeObjProperty(webSite);
    console.log(webSite.siteUrl);
}

//第3题
{
    async function async1() {
        console.log('1');
        await async2();
        console.log('2');
    }

    async function async2() {
        console.log('3');
    }

    console.log('4');

    setTimeout(function () {
        console.log('5');
    }, 0);

    async1();
    new Promise(function (resolve) {
        console.log('6');
        resolve();
    }).then(function () {
        console.log('7');
    });
    console.log('8');

    // 4 1 3 6 8 2 7 5
}


//第4题
{
    var b = 10;
    (function b() {
        b = 20;
        console.log(b); //输出函数b
    })();
    // 特性:声明提前:一个声明在函数体内都是可见的,函数声明优先于变量声明;
    // 在非匿名自执行函数中,函数变量为只读状态无法修改。
}

//第5题
{
    // var obj = {
    //     '2': 3,
    //     '3': 4,
    //     'length': 2,
    //     'splice': Array.prototype.splice,
    //     'push': Array.prototype.push
    // }; // [undefined, undefined, 3, 4];
    // obj.push(1); //根据length，往arr[2]上开始插入
    // obj.push(2);
    // console.log(obj); // {2: 1, 3: 2, length: 4}

    // var obj = {
    //     '2': 3,
    //     '3': 4,
    //     'length': 1,
    //     'splice': Array.prototype.splice,
    //     'push': Array.prototype.push
    // }; // [undefined, undefined, 3, 4];
    // obj.push(1); //根据length，往arr[1]上开始插入
    // obj.push(2);
    // console.log(obj); // {1: 1, 2: 2, 3: 4, length: 4}

    // var obj = {
    //     '2': 3,
    //     '3': 4,
    //     'length': 0,
    //     'splice': Array.prototype.splice,
    //     'push': Array.prototype.push
    // };  // [undefined, undefined, 3, 4];
    // obj.push(1); //根据length，往arr[0]上开始插入
    // obj.push(2);
    // console.log(obj); // {0: 1, 1: 2, 2: 3, 3: 4, length: 2}

    var obj = {
        '2': 3,
        '3': 4,
        'length': 3,
        'splice': Array.prototype.splice,
        'push': Array.prototype.push
    }; // [undefined, undefined, 3， 4];
    obj.push(1); //根据length，往arr[3]上开始插入
    obj.push(2);
    console.log(obj); // {2: 3, 3: 1, 4: 2, length: 5}
}

//第6题
{
    var a = { n: 1 };
    var b = a;
    // a.x = a = { n: 2 }; 
    a = a.x = { n: 2 }; // 上下结果是一样，所以如果想象为连续赋值同时进行最容易理解
    console.log(a.x); // undefined
    console.log(b.x); // {n: 2}
}

// 第7题
{
    var a = {}, b = '123', c = 123;
    a[b] = 'b';
    a[c] = 'c';
    console.log(a[b]); // c

    // example 2
    var a = {}, b = Symbol('123'), c = Symbol('123');
    a[b] = 'b';
    a[c] = 'c';
    console.log(a[b]); // b 这时a是：{Symbol(123):'b', Symbol(123):'c'}。b和c转成字符串虽然是一个，但底层还是认为是2个东西

    //---------------------// example 3
    var a = {}, b = { key: '123' }, c = { key: '456' };
    a[b] = 'b';
    a[c] = 'c';
    console.log(a[b]); // c，这时key值是：[object Object]
}

//第8题
{
    let a = ({} + {}).length; // [object Object][object Object]
    let b = ([] + []).length; // ""
    let c = (function () { }).length;
    console.log('第8题答案：', a, b, c); // 30 0 0
}

//第9题
// 编写一个程序将数组扁平化去并除其中重复部分数据，最终得到一个升序且不重复的数组
{
    var arr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]]], 10];
    console.log('第9题答案：', Array.from(new Set(arr.flat(Infinity))).sort((a, b) => a - b));

    var flat = function (arr, res = []) {
        for (let i = 0; i < arr.length; i++) {
            const ele = arr[i];
            if (Array.isArray(ele)) {
                flat(ele, res);
            } else {
                if (!res.includes(ele)) {
                    res.push(ele);
                }
            }
        }
        return res;
    };
    console.log('第9题答案2：', flat(arr, []).sort((a, b) => a - b));
}

// 第10题
// 给定两个数组，写一个方法来计算它们的交集。例如：给定 nums1 = [1, 2, 2, 1]，nums2 = [2, 2]，返回 [2, 2]。
{
    var nums1 = [1, 2, 2, 1];
    var nums2 = [2, 2];

    var res = nums1.reduce((pre, cur) => {
        if (nums2.includes(cur)) {
            pre.push(cur);
        }
        return pre;
    }, []);
    console.log('第10题答案：', res);
}

// 第11题
// 随机生成一个长度为 10 的整数类型的数组，例如 [2, 10, 3, 4, 5, 11, 10, 11, 20]
// 将其排列成一个新数组，要求新数组形式如下，例如 [[2, 3, 4, 5], [10, 11], [20]]。
{
    var generateRandomArr = function (len) {
        // const arr = new Array(len);
        // arr.fill();
        // return arr.map(() => Math.round(Math.random() * 100));
        return Array.from(new Array(len)).map(() => Math.round(Math.random() * 30));
    };
    let arr = generateRandomArr(10)
    console.log('第11题随机数组为：', arr);

    var sort = function (arr) {
        return arr.reduce(function (pre, cur) {
            const num = Math.floor(cur / 10);
            if (!pre[num]) {
                pre[num] = [];
            }
            pre[num].push(cur);
            return pre;
        }, []);
    };
    arr = Array.from(new Set(arr));
    arr.sort((a, b) => a - b);
    console.log('第11题答案为：', sort(arr));

}

// 第12题
// 如何把一个字符串的大小写取反（大写变小写，小写变大写），例如 ’AbC' 变成 'aBc'
{
    var str = 'AbCdEFaaee';
    var newStr = '';
    for (let i = 0; i < str.length; i++) {
        var code = str[i];
        if (code.toLowerCase() === code) { // 代表是小写
            newStr += code.toUpperCase();
        } else {
            newStr += code.toLowerCase();
        }
    }
    console.log('第12题答案为：', newStr);
}

// 第13题
// 实现一个字符串匹配算法，从长度为 n 的字符串 S 中，查找是否存在字符串 T，T 的长度是 m，若存在返回所在位置
{
    var S = 'abcd';
    var T = 'bc';

    var find = function (S, T) {
        var n = S.length;
        var m = T.length;
        if (n < m) {
            return -1;
        }
        if (n === m && S !== T) {
            return -1
        }
        var index;
        var num = 0;
        for (let i = 0; i < m; i++) {
            for (let j = 0; j < n; j++) {
                if (T[i] !== S[j]) {
                    continue;
                }
                num++;
                if (!index) {
                    index = j;
                }
            }
        }
        if (num === m) {
            return index;
        } else {
            return -1;
        }
    };

    console.log('第13题答案：', find(S, T));
}

// 第14题
// 用 JavaScript 写一个函数，输入 int 型，返回整数逆序后的字符串。
// 如：输入整型 1234，返回字符串“4321”。
// 要求必须使用递归函数调用，不能用全局变量，输入函数必须只有一个参数传入，必须返回字符串
{
    var func = function (num) {
        var str = num.toString();
        var newStr = str.slice(-1);
        if (newStr) {
            var left = str.slice(0, -1);
            newStr += func(left);
        }
        return newStr;
    };

    console.log('第14题答案：', func(1234));

}

// 第15题
/**
 * 将数字变成 0 的操作次数
    给你一个非负整数 num ，请你返回将它变成 0 所需要的步数。 如果当前数字是偶数，你需要把它除以 2 ；否则，减去 1 。
    示例 1：
    输入：num = 14
    输出：6
    解释：
    步骤 1) 14 是偶数，除以 2 得到 7 。
    步骤 2） 7 是奇数，减 1 得到 6 。
    步骤 3） 6 是偶数，除以 2 得到 3 。
    步骤 4） 3 是奇数，减 1 得到 2 。
    步骤 5） 2 是偶数，除以 2 得到 1 。
    步骤 6） 1 是奇数，减 1 得到 0 。
    示例 2：
    输入：num = 8
    输出：4
    解释：
    步骤 1） 8 是偶数，除以 2 得到 4 。
    步骤 2） 4 是偶数，除以 2 得到 2 。
    步骤 3） 2 是偶数，除以 2 得到 1 。
    步骤 4） 1 是奇数，减 1 得到 0 。
    示例 3：
    输入：num = 123
    输出：12
 */
{

    var func = function (num, count = 0) {
        if (num === 0) {
            return count;
        }
        if (num === 1) {
            return count + 1;
        }
        if (num % 2 == 0) { // 偶数
            var res = num / 2;
            count++;

            count = func(res, count);
        } else { //奇数
            var res = Math.ceil(num / 2);
            count++;

            res--;
            count++;

            count = func(res, count);
        }
        return count;
    };
    console.log('第15题答案：', func(123));
}

// 第16题
/**
 * 给你一个以行程长度编码压缩的整数列表 nums 。
考虑每对相邻的两个元素 freq, val] = [nums[2i], nums[2i+1]] （其中 i >= 0 ），
每一对都表示解压后子列表中有 freq 个值为 val 的元素，你需要从左到右连接
所有子列表以生成解压后的列表。
请你返回解压后的列表

示例：
输入：nums = [1,2,3,4]
输出：[2,4,4,4]
解释：第一对 [1,2] 代表着 2 的出现频次为 1，所以生成数组 [2]。
第二对 [3,4] 代表着 4 的出现频次为 3，所以生成数组 [4,4,4]

示例 2：
输入：nums = [1,1,2,3]
输出：[1,3,3]
提示：
 2 <= nums.length <= 100
 nums.length % 2 == 0
 1 <= nums[i] <= 100
 */
{
    // var nums = [1, 2, 3, 4];
    // var nums = [1, 1, 2, 3];
    var nums = [1, 1, 2, 3, 4, 8];
    var res = [];
    for (let i = 0; i < nums.length; i += 2) {
        var count = nums[i];
        var val = nums[i + 1];
        res.push(...new Array(count).fill(val));
    }
    console.log('第16题：', res);
}

//第17题
// 整数的各位积和之差
{
    // var n = 234;
    var n = 4421;
    var func = function (n) {
        var str = n.toString();
        var sum = 0;
        var ji = 1;
        for (let i = 0; i < str.length; i++) {
            var num = Number(str[i]);
            ji *= num;
            sum += num;
        }
        return Math.abs(ji - sum);
    }
    console.log('第17题：', func(n));
}

//第18题：猜数字
{
    var guess = [1, 2, 3];
    var answer = [2, 1, 3];

    var num = 0;
    for (let i = 0; i < guess.length; i++) {
        if (guess[i] === answer[i]) {
            num++;
        }
    }
    console.log('第18题：', num);
}

//第19题：统计位数为偶数的数字
{
    // var nums = [12, 345, 2, 6, 7896];
    var nums = [555, 901, 482, 1771];
    var count = 0;
    for (let i = 0; i < nums.length; i++) {
        if (nums[i].toString().length % 2 === 0) {
            count++;
        }
    }
    console.log('第19题：', count);
}

// 第20题：编写一个函数，不用临时变量，直接交换 numbers = [a, b]中 a 与 b 的值
/**
 * 例如交换两个整数a=10100001，b=00000110的值，可通过下列语句实现：
  a = a^b； 　　//a=10100111
  b = b^a； 　　//b=10100001
  a = a^b； 　　//a=00000110
 */
{
    var nums = [1.123, 2.44];

    var func = function (nums) {
        // [nums[0], nums[1]] = [nums[1], nums[0]]; 
        // var a = nums[0];
        // var b = nums[1];

        // nums[0] = nums[0] ^ nums[1];
        // nums[1] = nums[0] ^ nums[1];
        // nums[0] = nums[0] ^ nums[1];

        nums[0] = nums[0] + nums[1];
        nums[1] = nums[0] - nums[1];
        nums[0] = nums[0] - nums[1];
    };
    func(nums);
    console.log('第20题：', nums);
}